package cn.ts.aspect;

import cn.ts.annotation.RateLimit;
import cn.ts.entity.RateLimiterEntity;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import com.google.common.util.concurrent.RateLimiter;

import javax.annotation.Resource;

@Slf4j
@Aspect
@Component
public class RateLimitAspect {

    @Resource
    private Map<String, AbstractRateLimiter> rateLimiterGroup;

    private final Cache<String, RateLimiter> rateLimiters = CacheBuilder.newBuilder()
        .expireAfterWrite(10, TimeUnit.SECONDS)
        .build();

    // 个人限频黑名单24h - 分布式业务场景，可以记录到 Redis 中
    private final Cache<String, Long> blacklist = CacheBuilder.newBuilder()
            .expireAfterWrite(24, TimeUnit.HOURS)
            .build();

    /**
     * 在带有 @RateLimit 注解的方法执行前进行限流检查
     * 
     * @param joinPoint 连接点，包含被拦截方法的信息
     * @throws Throwable 如果请求过于频繁，抛出 RuntimeException
     */
    @Before("@annotation(cn.ts.annotation.RateLimit)")
    public void before(JoinPoint joinPoint) throws Throwable {

        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取目标方法
        Method method = signature.getMethod();
        // 获取方法上的 @RateLimit 注解
        RateLimit rateLimit = method.getAnnotation(RateLimit.class);


        String limitType = rateLimit.limitType();
        // 获取方法的参数值
        Object[] args = joinPoint.getArgs();
        String userId = null;
        // 遍历参数，找到名为 userid 的参数
        for (int i = 0; i < args.length; i++) {
            if (signature.getParameterNames()[i].equals("userId") && args[i] instanceof String) {
                userId = (String) args[i];
                break;
            }
        }
        // 生成请求的唯一键，加入 userid
        String key = method.getDeclaringClass().getName() + "." + method.getName();
        if (userId == null) {
            return;
        }
        if (userId != null) {
            key += "." + userId;
        }

        RateLimiterEntity rateLimiterEntity = RateLimiterEntity.builder()
                .rateLimit(rateLimit)
                .userId(userId)
                .key(key).build();


        AbstractRateLimiter rateLimiter = rateLimiterGroup.get(limitType);


        boolean limitCheck = rateLimiter.rateLimit(rateLimiterEntity);

        if (limitCheck){
            throw new RuntimeException("请求过于频繁，请稍后再试");
        }

        log.info("限流检查通过，方法：{}，参数：{}", method.getName(), args);


    }
}